package it.univpm.diiga.memorysim.kernel.shared;



//import it.univpm.diiga.memorysim.kernel.shared.tree.MovingBox;

import it.univpm.diiga.memorysim.kernel.IAlgorithmHDD;
import it.univpm.diiga.memorysim.kernel.IAlgorithmMemory;
import it.univpm.diiga.memorysim.kernel.IMemoryElement;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;

//import de.vogella.extensionpoint.definition.IGreeter;


public class Parameters {
	
	//tipo di simulazioni: 1=memcentrale  2=memsecondaria  3=ibrida
	private static int simulationType;
	
	// Valori di prova per gli algoritmi
	private String[] memCentral=new String[]{"Random"};
	private String[] memSecondary=new String[]{"Dummy"};
	
	//Caratteristiche Sistema
	private static int dimMem =450;
	private static int dimSwap = 0;
	private static int dimPage=0; // in byte
	private static int dimSOMemory=200; //area riservata al sistema operativo
	
	//HHD 
	private static int dimension; //  [Gb]
	private static int seekTime;
	private static long blockSize;  //-> trasfer= blocksize/trasferrate
	private static int trasferRate;
	private static int revolutionTime; // -> latencytime= revolutiontime/2
	private static long numBlock;
	
	
	private static int countPageFaultHDD=0;
	
	
	//Elenco dei processi
	private static List<ProcessRequest> processList;
	private static List <FileRequest> fileList;
	
	//  Metodo di allocazione
	private static int AllocationMethod;	
	/*
	 * 
	 * Metodo di allocazione:
	 * 0: metodo di allocazione contigua;
	 * 1: metodo di allocazione concatenata;
	 * 2: metodo di allocazione indicizzata; 
	 * 
	 */
	
	
	// Simulation sequence 
	//private static ArrayList<it.univpm.diiga.memorysim.kernel.shared.StepProcSim> SequenzaSimulazioneProcessi;
	//private static ArrayList <it.univpm.diiga.memorysim.kernel.shared.StepFileSim> SequenzaSimulazioneFile;
	//private static List<MemoryElement> sequence=new ArrayList<MemoryElement>();

	/*
	 * STRUTTURE MEMORIA
	 */
	/////	parte di memoria dedicata al SO contenente le tabelle dell pagine o dei segmenti o dei file aperti
	private static Hashtable<Integer, IMemoryElement> SOMemory=new Hashtable<Integer, IMemoryElement>();
	private static int positionSOMemory=0;
	////    parte di memoria deidicata al SO contenente la tabella dei file aperti
	private static List<Integer> SOMemoryFile=new ArrayList<Integer>();
	
	private static List<IMemoryElement> processMemory=new ArrayList<IMemoryElement>();
	private static int positionProcessMemory=0;
	private static int dimProcessMem=dimMem-dimSOMemory;
	//private static int dimProcessMem=300;
	
	private static List<IMemoryElement> swap=new ArrayList<IMemoryElement>();
	private static int positionSwap=0;
	
	private static List<IMemoryElement> emptyBlockMem = new ArrayList<IMemoryElement>();
	private static List<IMemoryElement> emptyBlockSwap = new ArrayList<IMemoryElement>();
	
	private static List<IAlgorithmMemory> algorithmListPag = new ArrayList<IAlgorithmMemory>();
	private static List<IAlgorithmMemory> algorithmListSeg = new ArrayList<IAlgorithmMemory>();
	private static IAlgorithmMemory algorithmSelectedMem;
	
	private static List<Event> eventsMemory=new ArrayList<Event>();

	
	//private static ArrayList<Integer> memory;
	
	//private static MovingBox root_disk;
	
	
	//TABELLA DEI FILE APERTI
	
	//tabella file aperti per processo
	//private static List<FileCtrlBlock> openFileTable=new ArrayList<FileCtrlBlock>();
	
	//ROOT DIRECTORY
	private static List<ElementRootDir> directoryStructure=new ArrayList<ElementRootDir>();
	
	//tabella generale dei file aperti
	private static List<FileCtrlBlock> openFileTable=new ArrayList<FileCtrlBlock>();
	
	//tabella dei file controll block in mem secondaria
	private static List<FileCtrlBlock> fcbTable=new ArrayList<FileCtrlBlock>();
	
	//tabella dei file sull'HDD
	//private static List<FileCtrlBlock> fileTable=new ArrayList<FileCtrlBlock>();
	
	//lista degli elementi vuoti nell'HD
	private static List<HDDElementEmpty> HDDEmptyElement = new ArrayList<HDDElementEmpty>();
	
	//lista degli elementi pieni nell'HD
	private static List<FileElement> HDDFileElement = new ArrayList<FileElement>();
	
	//lista degli eventi riferiti all'hdd
	private static List<Event> eventsHDD=new ArrayList<Event>();
	
	//lista degli algoritmi per la gestione dell'HDD
	private static ArrayList<IAlgorithmHDD> algorithmListHDD = new ArrayList<IAlgorithmHDD>();
	
	private static IAlgorithmHDD algorithmSelectedHDD;
	
	
	
	/// TIPO SIMULAZIONE
	public static void setSimulationType(int type){		
		simulationType=type;
	}
	
	public static int getSimulationType(){
		
		return simulationType;
	}
	
	
	public static void setAlgorithmSelectedPag(IAlgorithmMemory alg){
		algorithmSelectedMem = alg;
	}
	
	public static void setAlgorithmSelectedSeg(IAlgorithmMemory alg){
		algorithmSelectedMem = alg;
	}
	
	public static void setAlgorithmSelectedPag(int position){
		if (algorithmListPag.size()>0)
			algorithmSelectedMem = algorithmListPag.get(position);
	}
	
	public static void setAlgorithmSelectedSeg(int position){
		if (algorithmListSeg.size()>0)
			algorithmSelectedMem = algorithmListSeg.get(position);
	}
	
	public static void setAlgorithmSelectedHDD(int position){
		if (algorithmListHDD.size()>0)
			algorithmSelectedHDD = algorithmListHDD.get(position);
	}
	
	public static void setDimPage(int dimPagePara){
		dimPage=dimPagePara;
	}

	
	public static int getDimPage(){
		return dimPage;
	}
	
	public static void setProcessList(List<ProcessRequest> processListPara){
		processList=processListPara;
	}
	
	public static  List<ProcessRequest> getProcessList(){
		return processList;
	}
	
	public static IAlgorithmMemory getAlgorithmSelectedMem(){
		return algorithmSelectedMem;
	}
	
	public static IAlgorithmHDD getAlgorithmSelectedHDD(){
		return algorithmSelectedHDD;
	}
	
	//// Lista dei file richiesti
	
	public static void setFileList(List<FileRequest> fileListPara){
		fileList= fileListPara;
	}
	
	public static  List<FileRequest> getFileList(){
		return fileList;
	}
	
	
	/*
	 * RECUPERO STRUTTURE
	 */
	
	public static Hashtable<Integer, IMemoryElement> getSOMemory(){
		return SOMemory;						
	}
	
	public static List<Integer> getSOMemoryFile(){
		return SOMemoryFile;
	}
	
	public static List<IMemoryElement> getProcessMemory(){
		return processMemory;
	}
	
	public static List<IMemoryElement> getSwap(){
		return swap;
	}
	
	public static List<IMemoryElement> getEmptyBlockMem(){
		return emptyBlockMem;
	}
	
	public static List<IMemoryElement> getEmptyBlockSwap(){
		return emptyBlockSwap;
	}
	
	/*public static List<MemoryElement> getSequenceOutput(){
		return sequence;
	}*/
	
	
	/*
	 * PUNTATORI STRUTTURE
	 */

	public static void setPositionSOMemory(int positionMemoryPara){
		positionSOMemory=positionMemoryPara;
	}
	
	public static int getPositionSOMemory(){
		return positionSOMemory;
	}
	
	
	public static void setPositionProcessMemory(int positionMemoryPara){
		positionProcessMemory=positionMemoryPara;
	}
	
	public static int getPositionProcessMemory(){
		return positionProcessMemory;
	}
	
	public static void setPositionSwap(int positionMemoryPara){
		positionSwap=positionMemoryPara;
	}
	
	public static int getPositionSwap(){
		return positionSwap;
	}
	
	public static void setProcessMemory(List<IMemoryElement> ls){
		processMemory = ls;
	}
	
	
	
	/*
	 * DIMENSIONI STRUTTURE
	 */
	
	public static int getDimSOMemory(){
		return dimSOMemory;
	}
	
	public static void setDimSOMemory(int dim){
		dimSOMemory=dim;
	}

	public static int getDimProcessMemory(){
		return dimProcessMem;
	}
	
	public static int getDimSwap(){
		return dimSwap;
	}
	
	public static int getDimMemory(){
		return dimMem;
	}
	
	public static boolean isPagination(){
		if (dimPage!=0)
			return true;
		else 
			return false;
	}
	//Creare metodi per restituire i tipi di funzionamento del kernel (paginazione, segmentazione), e algoritmi di sostituzione.

	
	
	
	
	/*
	 * Carica gli algoritmi contenuti nella cartella path.
	 * Gli algoritmi devono avere la classe principale MainAlgo che implementa Algorithm
	 * 
	 */
	private static final String IAlgorithm_ID = "it.univpm.diiga.memorysim.kernel.algorithm";
	public static void loadAlgorithm(){
		
		IConfigurationElement[] config = Platform.getExtensionRegistry()
				.getConfigurationElementsFor(IAlgorithm_ID);
		try {
			for (IConfigurationElement e : config) {
				System.out.println("Evaluating extension");
				final Object o = e.createExecutableExtension("class");
				
				if (o instanceof IAlgorithmHDD) {
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							System.out.println("Exception in client");
						}

						@Override
						public void run() throws Exception {
							IAlgorithmHDD algorithm = (IAlgorithmHDD) o;
							String algorithmType=((IAlgorithmHDD) o).getAlgorithmType();
							if(algorithmType.equalsIgnoreCase("hdd"))
								algorithmListHDD.add(algorithm);
							System.out.println(((IAlgorithmHDD) o).getAlgorithmName());
						}
					};
					SafeRunner.run(runnable);
				}else if (o instanceof IAlgorithmMemory) {
					
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							System.out.println("Exception in client");
						}

						@Override
						public void run() throws Exception {
							System.out.println("ci siamo///////////////////////////////////////////////////");
							IAlgorithmMemory algorithm = (IAlgorithmMemory) o;
							String algorithmType=((IAlgorithmMemory) o).getAlgorithmType();
							if(algorithmType.equalsIgnoreCase("paging"))
								algorithmListPag.add(algorithm);
							if(algorithmType.equalsIgnoreCase("segmentation"))
								algorithmListSeg.add(algorithm);
							System.out.println(((IAlgorithmMemory) o).getAlgorithmName());
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (CoreException ex) {
			System.out.println(ex.getMessage());
		}
	}
	
	/*public static void loadAlgorithm(){
			
			Class cls = null;
			Object o=null;
			String path = "src/it/univpm/diiga/memorysim/kernel/algo/"; 
			//String className = "MainAlgo";
			String archiveType="jar";
			
			File dir = new File (path);
			String className = null;
			String algorithmType = null;
		    JarFile jf;
			
		    

	       
			FileExtFilter fef = new FileExtFilter(archiveType);
	        String[] list = dir.list (fef);
	        
	        
	        for (int i = 0; i < list.length; i++)
	        {
	        	try {
						File file = new File(path+list[i]);
						URL url = file.toURI().toURL();
						URL[] urls = {url}; 
						//ClassLoader cl = new URLClassLoader(urls);
						//cls = cl.loadClass("FirstFit");
						//o = cls.newInstance();
						
							jf = new JarFile(file);
							Manifest mf = jf.getManifest();
							className = mf.getMainAttributes().getValue(new Attributes.Name("Algorithm-Class"));
							algorithmType = mf.getMainAttributes().getValue(new Attributes.Name("Algortihm-Type"));

						if (className!=null && algorithmType!=null ){
							Class<?> c = new URLClassLoader(urls).loadClass(className);
							o=c.newInstance();
							if(o instanceof AlgorithmMemory){
								AlgorithmMemory algorithm = (AlgorithmMemory) o;
								if(algorithmType.equalsIgnoreCase("paging"))
									algorithmListPag.add(algorithm);
								if(algorithmType.equalsIgnoreCase("segmentation"))
									algorithmListSeg.add(algorithm);
							}
							if(o instanceof AlgorithmHDD){
								AlgorithmHDD algorithm = (AlgorithmHDD) o;
								if(algorithmType.equalsIgnoreCase("hdd"))
									algorithmListHDD.add(algorithm);
								System.out.println(algorithmListHDD.get(0).getAlgorithmName());
							}
						}
				   
				} catch (MalformedURLException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        }
		}*/
	
	/*public static void setFileSystem(MovingBox root) {
		root_disk= root;
	}*/
	
	public static void setFileListRequest(List <FileRequest> files){
		fileList=files;
	}
	
	public static void setDimensionCentralMemory(int dimCentralMemory){
		dimMem=dimCentralMemory;
	}

	public static void setDimensionSwap(int DimSwap) {
		dimSwap=DimSwap;		
	}

	public static void setDimensionBlock(int DimBlock) {
		dimPage=DimBlock;		
	}

	public static void setSecondaryMemory(int HD_Dimension,int Seek, long BlockSize,int TrasferRate, int RevolutionTime) {
		dimension=HD_Dimension;
		seekTime=Seek;
		blockSize=BlockSize;
		trasferRate=TrasferRate;
		revolutionTime=RevolutionTime;
	}
	

	
	public String[] getSecondaryMemoryAlg(){
		return memSecondary;	
	}
	
	public String[] getCentralMemoryAlg(){
		return memCentral;
	}
	
	public static void addEvent(String eventType,ProcessRequest process){
		Event event=new Event(eventType,process);
		eventsMemory.add(event);
	}
	
	public static void addEvent(String eventType,FileRequest file){
		Event event=new Event(eventType,file);
		eventsHDD.add(event);
	}
	
	public static List<Event> getEventMem(){
		return eventsMemory;
	}
	
	public static List<Event> getEventHDD(){
		return eventsHDD;
	}
	
	
	public static int getCountPageFaultHDD(){
		return countPageFaultHDD;
	}
	
	public static void setCountPageFaultHDD(){
		countPageFaultHDD++;
	}
	
	////// OPERAZIONE SULLA TABELLA DEI FILE APERTI /////////////////////////
	
	
	public static void setRowOpenTable(FileCtrlBlock fcb){		
		//FileCtrlBlock newOpenFile=new FileCtrlBlock(id_file,id_block,dim);
		openFileTable.add(fcb);
	}
	
	public static FileCtrlBlock getRowOpenTable(int id_file){
		FileCtrlBlock fcb=null;
		for (int i=0;i<openFileTable.size();i++){
			if (openFileTable.get(i).getIdFile()==id_file){
				fcb=openFileTable.get(i);
				return fcb;
			}
		}
		
		return fcb;
	}
	
	public static void delRowOpenTable(int id_file){
		for (int i=0;i<openFileTable.size();i++){
			if (openFileTable.get(i).getIdFile()==id_file){
					openFileTable.remove(i);
					break;
			}
		}
	}
	
	public static List<FileCtrlBlock> getOpenTable(){
		return openFileTable;
	}
	
	///////////////////////////////////////////////////////////////////////////
	
	
	///////////////////////////////////        	METODI PER L'HDD                  ///////////////////////////
	
	public static int getDimensioneHDD(){
		return dimension;
	}
	public static long getBlockSizeHDD(){
		return blockSize;
	}
	
	public static List<HDDElementEmpty> getEmptyElementHDD(){
		return HDDEmptyElement;
	}
	
	public static void setEmptyElementHDD(HDDElementEmpty ele){
		HDDEmptyElement.add(ele);
	}
	
	
	public static List<FileElement> getHDDFileElement(){
		return HDDFileElement;
	}
	
	public static void setHDDFileElement(FileElement ele){
		HDDFileElement.add(ele);
	}
	
	
	public static long getNumBlock(){
		
		numBlock=((dimension*(1024*1024))/blockSize)*1024;
		//System.out.println("numero: "+(long)numBlock);
		return numBlock;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	public static int getAllocationMethod(){
		return AllocationMethod;
	}
	
	public static List<ElementRootDir> getElementStructure(){
		return directoryStructure;
	}
	
	public static void setElementStructure(ElementRootDir element){
		directoryStructure.add(element);		
	}
	
	public static ElementRootDir searchElement(int id_file){
		for(int i=0; i<directoryStructure.size();i++){
			if (id_file==directoryStructure.get(i).getIdFile())
				return directoryStructure.get(i);
		}
		return null;
	}
	
	public static void delDirectStructure(int idFile){
		for(int i=0;i<directoryStructure.size();i++){
			if (idFile==directoryStructure.get(i).getIdFile())
				directoryStructure.remove(i);
		}
		
	}
	

	
	public static List<FileCtrlBlock> getListfcb(){
		return fcbTable;
	}
	
	public static void setListfcb(FileCtrlBlock fcb){
		fcbTable.add(fcb);
	}
	
}

	

